<template>
  <SubViewContainer>
    <ElCard v-loading="isTableLoading">
      <FirewallInstanceSelector
        v-model:firewall="firewallInstance"
        @update:firewall="onFirewallChange"
      />
      <div class="table-controller">
        <div class="filters">
          <!-- TODO: 等防火墙支持 ipv6 后，重新开启 ip version 选择器 -->
          <!-- <IpVersionSelector v-model:version="filters.ipVersion" /> -->
          <ElDatePicker
            v-model="filters.timeRange"
            type="datetimerange"
            class="date-range-picker"
            :format="t('dateFormatter')"
            :value-format="Enums.REMOTE_DATE_FORMATTER"
          />
          <ProtoSelector v-model:proto="filters.proto" />
          <ApplicationSelector v-model:application="filters.app" />
          <NetworkDirectionSelector v-model:direction="filters.direction" />
          <ActionSelector v-model:action="filters.action" />
          <ElInput
            v-model="filters.s_ip"
            class="search-input"
            :placeholder="t('searchBySourceIp')"
            @keyup.enter="onFiltersChange"
          />
          <ElInput
            v-model="filters.d_ip"
            class="search-input"
            :placeholder="t('searchByTargetIp')"
            @keyup.enter="onFiltersChange"
          />
          <ElInput
            v-model="filters.s_port"
            class="search-input"
            :placeholder="t('searchBySourcePort')"
            @keyup.enter="onFiltersChange"
          />
          <ElInput
            v-model="filters.d_port"
            class="search-input"
            :placeholder="t('searchByTargetPort')"
            @keyup.enter="onFiltersChange"
          />
          <ElButton :icon="Search" @click="onTableRefresh" />
        </div>
      </div>
      <TableWithPagination
        v-model:paginationPageSize="pagination.pageSize"
        v-model:paginationCurrentPage="pagination.currentPage"
        size="small"
        :data="logs"
        :paginationTotal="pagination.total"
        :onUpdate:paginationPageSize="onFiltersChange"
        :onUpdate:paginationCurrentPage="onFiltersChange"
        paginationLayout="sizes, total, prev, pager, next"
      >
        <ElTableColumn :label="t('recordedAt')" min-width="120">
          <template #default="{ row }">
            {{dayjs.unix(row.terminal_time).format(t('dateMinuteFormatter'))}}
          </template>
        </ElTableColumn>
        <ElTableColumn :label="t('sourceIp')" prop="s_ip" />
        <ElTableColumn :label="t('sourcePort')" prop="s_port" width="70" />
        <ElTableColumn :label="t('destinationIp')" prop="d_ip" />
        <ElTableColumn :label="t('destinationPort')" prop="d_port" width="70" />
        <ElTableColumn :label="t('proto')">
          <template #default="{ row }">
            {{t(`protoList.${row.proto}`) || '--'}}
          </template>
        </ElTableColumn>
        <ElTableColumn :label="t('application')" >
          <template #default="{ row }">
            {{Application.getOneById(row.app_id)?.name || '----'}}
          </template>
        </ElTableColumn>
        <ElTableColumn :label="t('direction')" min-width="80">
          <template #default="{ row }">{{t(`directions.${row.dir}`)}}</template>
        </ElTableColumn>
        <ElTableColumn :label="t('action')">
          <template #default="{ row }">{{t(`actions.${row.dir}`)}}</template>
        </ElTableColumn>
        <ElTableColumn :label="t('flowBytes')" min-width="80">
          <template #default="{ row }">{{formatBytes(row.origin_bytes)}}</template>
        </ElTableColumn>
        <ElTableColumn :label="t('flowPackets')" prop="origin_packets" width="70" />
        <ElTableColumn :label="t('ruleName')" min-width="160" show-overflow-tooltip>
          <template #default="{ row }">{{row.rule_name || '----'}}</template>
        </ElTableColumn>
      </TableWithPagination>
    </ElCard>
  </SubViewContainer>
</template>

<script setup lang="ts">
import { Search } from '@element-plus/icons-vue';
import dayjs from 'dayjs';

import SubViewContainer from '@core/components/subLayout/SubViewContainer.vue';
import TableWithPagination from '@core/components/TableWithPagination.vue';
import * as Enums from '@firewall/engine/Enums';
import { FirewallSummary } from '@firewall/engine/Firewall';
import LogService, { FetchRawLogParams, RawLog, LogSetting } from '@firewall/engine/LogService';
import Application from '@firewall/engine/Application';

const { t } = useI18n({ inheritLocale: true, useScope: 'local' });

const isTableLoading = ref(false);

const filters = reactive({
  ipVersion: Enums.IpVersion.V4,
  app: Enums.FILTER_ALL,
  proto: Enums.AccessProtocol.All,
  direction: Enums.NetworkDirection.All,
  action: Enums.AccessControlAction.All,
  s_ip: '',
  s_port: '',
  d_ip: '',
  d_port: '',
  timeRange: [
    dayjs().add(-1, 'days').format(Enums.REMOTE_DATE_FORMATTER),
    dayjs().format(Enums.REMOTE_DATE_FORMATTER),
  ],
});
const pagination = reactive({
  pageSize: 10,
  currentPage: 1,
  total: 0,
});
const getFetchParams = (): FetchRawLogParams | null => {
  if (!logSetting.logUserId || !logSetting.auditGroupId || !logSetting.auditFlowId) {
    return null;
  }
  return {
    userid: logSetting.logUserId,
    loggroup: logSetting.auditGroupId,
    logunit: logSetting.auditFlowId,
    page: pagination.currentPage,
    size: pagination.pageSize,
    start_time: dayjs(filters.timeRange[0]).format(Enums.REMOTE_DATE_FORMATTER),
    end_time: dayjs(filters.timeRange[1]).format(Enums.REMOTE_DATE_FORMATTER),
    is_full_index: Enums.RequestBoolean.True,
    judge_mode: Enums.LogJudgeMode.Equal,
    keys: [
      { key: 'ip_proto', value: filters.ipVersion, judge_mode: Enums.LogJudgeMode.Equal },
      { key: 'proto', value: filters.proto, judge_mode: Enums.LogJudgeMode.Equal },
      { key: 'app_id', value: filters.app, judge_mode: Enums.LogJudgeMode.Equal },
      { key: 'dir', value: filters.direction, judge_mode: Enums.LogJudgeMode.Equal },
      { key: 'action', value: filters.action, judge_mode: Enums.LogJudgeMode.Equal },
      {
        key: 's_ip',
        value: filters.s_ip,
        judge_mode: Enums.LogJudgeMode.FuzzyMatching,
      },
      {
        key: 's_port',
        value: filters.s_port,
        judge_mode: Enums.LogJudgeMode.FuzzyMatching,
      },
      {
        key: 'd_ip',
        value: filters.d_ip,
        judge_mode: Enums.LogJudgeMode.FuzzyMatching,
      },
      {
        key: 'd_port',
        value: filters.d_port,
        judge_mode: Enums.LogJudgeMode.FuzzyMatching,
      },
    ],
  };
};
const firewallInstance = reactive({} as Partial<FirewallSummary>);
const logSetting = reactive({} as Partial<LogSetting>);
const refreshLogSetting = async () => {
  if (!firewallInstance.firewallId) {
    return;
  }
  isTableLoading.value = true;
  try {
    const remoteSetting = await LogService.fetchSetting({ firewallId: firewallInstance.firewallId });
    Object.assign(logSetting, remoteSetting);
  } finally {
    isTableLoading.value = false;
  }
};

const logs = ref([] as Array<RawLog>);
const refreshTable = async () => {
  const fetchParams = getFetchParams();
  if (!fetchParams) {
    return;
  }
  isTableLoading.value = true;
  try {
    const response = await LogService.fetchRawLogs(fetchParams);
    logs.value = response.raw_logs || [];
    pagination.total = response.total || 0;
  } finally {
    isTableLoading.value = false;
  }
  LogService.fetchRuleNameOfLogs(logs.value, firewallInstance.firewallId);
};

const formatBytes = (bytes: string) => {
  // TODO: 按需求添加 B、K、M、G、T 等单位的处理
  return `${bytes}${t('quantifierOfByte')}`;
};

const onTableRefresh = async () => {
  await refreshTable();
};
const onFirewallChange = async (newInstance: FirewallSummary) => {
  Object.assign(firewallInstance, newInstance);
  await refreshLogSetting();
  await refreshTable();
};
const onFiltersChange = async () => {
  await refreshTable();
};
</script>

<i18n lang="yaml" locale="zh-CN">
  searchBySourceIp: '输入源IP'
  searchByTargetIp: '输入目的IP'
  searchBySourcePort: '输入源端口'
  searchByTargetPort: '输入目的端口'
  recordedAt: '发生时间'
  sourceIp: '源IP地址'
  sourcePort: '源端口'
  destinationIp: '目的IP地址'
  destinationPort: '目的端口'
  proto: '协议'
  protoList:
    1: ICMP
    6: TCP
    17: UDP
    58: ICMPv6
  application: '应用'
  direction: '方向'
  directions:
    1: '内对外'
    2: '外对内'
  action: '动作'
  actions:
    1: '放行'
    2: '阻断'
  flowBytes: '流字节数'
  quantifierOfByte: 'B'
  flowPackets: '流报文数'
  ruleName: '规则名'
  searchType:
    sourceIp: '来源 IP'
    destinationIp: '目的 IP'
  searchTypePort:
    sourcePort: '来源端口'
    destinationPort: '目的端口'
  dateFormatter: 'YYYY-MM-DD HH:mm:ss'
  dateMinuteFormatter: 'YYYY-MM-DD HH:mm'
</i18n>
<style lang="scss" scoped>
.table-controller {
  display: flex;
  flex-direction: column;
  margin-top: 10px;

  .filters {
    display: flex;
    flex-flow: wrap;
    align-self: flex-end;
    justify-content: flex-end;
    max-width: 1100px;

    & > :deep(*) {
      flex-grow: 0;
      margin: 0 0 10px 10px;
    }
  }
}

.search-input {
  width: 200px;
  margin-right: 3px;

  :deep(.el-input__inner) {
    line-height: var(--el-input-height);
  }
}

</style>
